/* Blink Example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"

#include "nvs_flash.h"
#include "nvs.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include <lwip/netdb.h>
#include "esp_log.h"
#include "sdkconfig.h"

#include "gw-device.h"

#include "LoRaPhy_interface.h"
#include "loragw_gpio.h"
#include "lora_pkt_fwd.h"
#include "console_app.h"
#include "internet_common.h"
#include "sntp_app.h"
#include "lora_pkt_fwd.h"
#include "esp_lora.h"


bool is_reconnecting = false;
uint32_t last_connect_time = 0;

void device_start_up(void);

int network_environment_init()
{
    esp_err_t err = nvs_flash_init();
    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
        // NVS partition was truncated and needs to be erased
        // Retry nvs_flash_init
        ESP_ERROR_CHECK(nvs_flash_erase());
        err = nvs_flash_init();
    }
    ESP_ERROR_CHECK( err );

    config_para_t temp_device_settings = {0};
    err = read_settings_from_nvs();
    if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) 
    {
        ESP_ERROR_CHECK(err);
    }

    get_device_settings(&temp_device_settings);

   	gpio_pad_select_gpio(4);
	/* Set the GPIO as a push/pull output */
	gpio_set_direction(4, GPIO_MODE_OUTPUT);    

    /****************************** INTERNET INIT ******************************/
    /****************************************************************************/
    internet_common_init();

    int count = 0;
    while(connect_without_init(&temp_device_settings)==false)
    {
        count++;
        if(count >= 5)//至多重连5次，5次都连不上，则重启
        {
            esp_restart();
        }
    }
    /*************************INTERNET INIT END**********************************/
   
    return 0;
}


void network_indicate()
{
    net_info_t net_info_indi;
    
    gpio_pad_select_gpio(NETWORK_INDICATION_LED);
    gpio_set_direction(NETWORK_INDICATION_LED, GPIO_MODE_OUTPUT);

    gpio_set_level(NETWORK_INDICATION_LED,INDICATION_LED_OFF);

    TickType_t flashing_time = xTaskGetTickCount();

    while(1)
    {
        get_net_info(&net_info_indi);
        switch(net_info_indi.net_interface)
        {
        case NET_INTERFACE_ERROR:
            //无联网不闪烁
            gpio_set_level(NETWORK_INDICATION_LED,INDICATION_LED_OFF); 
            // ESP_LOGI("network_indicate","NET ERROR");           

            break;

            case NET_INTERFACE_WIFI:
            //WIFI 0.5s 闪烁
            if(xTaskGetTickCount() > flashing_time )
            {
                flashing_time += 200/portTICK_PERIOD_MS;
                gpio_set_level(NETWORK_INDICATION_LED,INDICATION_LED_ON);
            }
            else
            {
                gpio_set_level(NETWORK_INDICATION_LED,INDICATION_LED_OFF);   
            }          

            break;

        case NET_INTERFACE_ETH:
            //ETH 1S 闪烁
            if(xTaskGetTickCount() > flashing_time)
            {
                flashing_time += 500/portTICK_PERIOD_MS;
                gpio_set_level(NETWORK_INDICATION_LED,INDICATION_LED_ON);
            }
            else
            {
                gpio_set_level(NETWORK_INDICATION_LED,INDICATION_LED_OFF);   
            }

            break;

        case NET_INTERFACE_4G:
            //4G 2s 闪烁
            if(xTaskGetTickCount() > flashing_time )
            {
                flashing_time += 1000/portTICK_PERIOD_MS;
                gpio_set_level(NETWORK_INDICATION_LED,INDICATION_LED_ON);
            }
            else
            {
                gpio_set_level(NETWORK_INDICATION_LED,INDICATION_LED_OFF);   
            }          

            break;
        }

        vTaskDelay(100/portTICK_PERIOD_MS);
    }
}

static int work_prepare_init()
{
 /*************************LORA DRIVER INIT***********************************/
 /****************************************************************************/
    gpio_pad_select_gpio(PIN_NUM_RF_RESET);
    gpio_set_direction(PIN_NUM_RF_RESET, GPIO_MODE_OUTPUT);
    gpio_set_level(PIN_NUM_RF_RESET, 1);

    spi_init();

    printf("SX1276 Version:0x%.2x",Radio.Read(0x42));

    config_para_t* temp_device_settings = (config_para_t*)malloc(sizeof(config_para_t));
    if(temp_device_settings == NULL)
    {
        ESP_LOGE("work_prepare","no space space");
        return -1;
    }

    get_device_settings(temp_device_settings);

    RF_Parameters_t rf_parameter;

    rf_parameter.bandwidth = BANDWIDTH_125KHZ;
    rf_parameter.coderate = LORA_CR_4_5;
    rf_parameter.crc = true;
    rf_parameter.datarate = temp_device_settings->sf;
    rf_parameter.freq_hz = temp_device_settings->rf_freq;
    rf_parameter.invert_pol = false;
    rf_parameter.modulation = MODULATION_LORA;
    rf_parameter.preamble = 8;
    rf_parameter.rf_power = 20;
    rf_parameter.SYNC_word = 0x34;
    interface_LoRaPhy_init(&rf_parameter);

    printf("LoRa Driver initialized...\n");

    uint64_t deviceID = getDeviceID();

    printf("DeviceID:%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x\n", (uint8_t)(deviceID>>56&0xff),(uint8_t)(deviceID>>48&0xff),
                                                        (uint8_t)(deviceID>>40&0xff),(uint8_t)(deviceID>>32&0xff),
                                                        (uint8_t)(deviceID>>24&0xff),(uint8_t)(deviceID>>16&0xff),
                                                        (uint8_t)(deviceID>>8&0xff),(uint8_t)(deviceID&0xff));

    setGWNetMac(deviceID>>32&0xffffffff,deviceID&0xffffffff);

    free(temp_device_settings);

    return 0;
}

static void work_task_init()
{
    //启动NTP
    sntp_app_init();//启动SNTP

    config_para_t* temp_device_settings = (config_para_t*)malloc(sizeof(config_para_t));
    if(temp_device_settings == NULL)
    {
        esp_restart();
    }

    get_device_settings(temp_device_settings);    

    //启动pkt-fwd
    lora_pkt_fwd_init((char*)(temp_device_settings->dataServer_ip),(char*)(temp_device_settings->dataServer_port));

    free(temp_device_settings);
}

void device_start_up()
{
    //初始化外设
    if(!work_prepare_init())//准备工作启动成功
    {
        //启动工作线程
        work_task_init();
    }
    else
    {
        esp_restart();
    }
}

void app_main()
{
    printf("system starting...\n");

    //运行控制台
    run_console();

    //网络状态指示
    xTaskCreate(&network_indicate, "network_indicate", 2048, NULL, 10, NULL);    

    set_gwStatus(NO_CONNECTION);

    //初始化网络环境
    if(!network_environment_init())
    {
        //设备启动
        device_start_up();

        //设置网关的状态为工作中
        set_gwStatus(WORKING);
    }
}
